﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System.Linq;
using ScrumTable.BL.DM.DataManagement;
using ScrumTable.Common.Collections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ScrumTable.DL.Data.Generic.Cache;
using ScrumTable.DL.Data.Generic.Test;
using ScrumTable.DL.Data.Local.Test;
using ScrumTable.DL.Data.Schema.ScrumTableV1;

#endregion

namespace ScrumTable.BL.DM.Test.DataManagement
{
    /// <summary>
    /// This is the test class for Task class.
    /// </summary>
    [TestClass]
    public class TaskTest : ScrumItemTest<Task, TaskSchema>
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets the default instance to test.
        /// </summary>
        protected override Task ToTest
        {
            get { return Context.Projects[Resources.Project1Id].Stories[Resources.UserStory1Id].Tasks[Resources.Task1Id]; }
        }

        private ScrumState ActiveState { get { return ToTest.ItemType.StateMappings[Resources.TaskActiveState]; } }
        private ScrumState InProgressState { get { return ToTest.ItemType.StateMappings[Resources.TaskInProgressState]; } }
        private ScrumState ClosedState { get { return ToTest.ItemType.StateMappings[Resources.TaskClosedState]; } }

        #endregion

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new TaskTest instance.
        /// </summary>
        public TaskTest()
        {
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Use TestInitialize to run code before running each test .
        /// </summary>
        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();
        }

        /// <summary>
        /// Use TestCleanup to run code after each test has run.
        /// </summary>
        [TestCleanup]
        public override void TestCleanup()
        {
            base.TestCleanup();
        }

        [TestMethod]
        public void TestChangeValueByMeta()
        {
            ToTest[DataObjectSchema.Description] = "[New Description]";
            ToTest[DataObjectSchema.Name] = "[New Name]";
            ToTest[DataObjectSchema[TestFieldDefinitionSet.PriorityFieldName]] = ToTest.ItemType.FieldMeta.TryGetByName(TestFieldDefinitionSet.PriorityFieldName).AllowedValues.ToEnumerable().Second();
        }

        [TestMethod]
        public void TestChangeValueByString()
        {
            ToTest[DataObjectSchema.Description.SchemaName] = "[New Description]";
            ToTest[DataObjectSchema.Name.SchemaName] = "[New Name]";
            ToTest[DataObjectSchema[TestFieldDefinitionSet.PriorityFieldName].SchemaName] = ToTest.ItemType.FieldMeta.TryGetByName(TestFieldDefinitionSet.PriorityFieldName).AllowedValues.ToEnumerable().Second();
        }

        [TestMethod]
        public void TestValueChangeOnDL()
        {
            TestValueChangeWithEventOnDL(DataObjectSchema.MemberId, Resources.FullMember2IdChain, "AssignedMember");
            TestValueChangeWithEventOnDL(DataObjectSchema.Description, "[New Description]");
            TestValueChangeWithEventOnDL(DataObjectSchema.Name, "[New Name]");
            TestValueChangeWithEventOnDL(DataObjectSchema.Ranking, 5.6);
            TestValueChangeWithEventOnDL(DataObjectSchema.Ranking, null);
            TestValueChangeWithEventOnDL(DataObjectSchema.Ranking, -18.0);
            TestValueChangeWithEventOnDL(DataObjectSchema.Ranking, 0.0);
            TestValueChangeWithEventOnDL(DataObjectSchema.State, ClosedState.Name);
            TestValueChangeWithEventOnDL(DataObjectSchema.CompletedWork, 1.5);
            TestValueChangeWithEventOnDL(DataObjectSchema.CompletedWork, null);
            TestValueChangeWithEventOnDL(DataObjectSchema.CompletedWork, 0.0);
            TestValueChangeWithEventOnDL(DataObjectSchema.CompletedWork, -15.0);
            TestValueChangeWithEventOnDL(DataObjectSchema.Estimate, 1.5);
            TestValueChangeWithEventOnDL(DataObjectSchema.Estimate, -1.5);
            TestValueChangeWithEventOnDL(DataObjectSchema.Estimate, 0.0);
            TestValueChangeWithEventOnDL(DataObjectSchema.Estimate, null);
            TestValueChangeWithEventOnDL(DataObjectSchema.RemainingWork, 1.5);
            TestValueChangeWithEventOnDL(DataObjectSchema.RemainingWork, null);
            TestValueChangeWithEventOnDL(DataObjectSchema.RemainingWork, -91.9);
            TestValueChangeWithEventOnDL(DataObjectSchema.RemainingWork, 0.0);

            TestValueChangeWithEventOnDL(
                DataObjectSchema[TestFieldDefinitionSet.ActivityFieldName],
                "Documentation");
            TestValueChangeWithEventOnDL(
                DataObjectSchema[TestFieldDefinitionSet.PriorityFieldName],
                ToTest.ItemType.FieldMeta.TryGetByName(TestFieldDefinitionSet.PriorityFieldName).AllowedValues.ToEnumerable().Second());
        }

        [TestMethod]
        public void TestValueChangeOnDM()
        {
            TestValueChangeWithEventOnDM("Ranking", 0.0);
            TestValueChangeWithEventOnDM("Ranking", -45.6);
            TestValueChangeWithEventOnDM("Ranking", 5.6);
            TestValueChangeWithEventOnDM("Ranking", null);
            TestValueChangeWithEventOnDM("State", ClosedState);
            TestValueChangeWithEventOnDM("CompletedWork", -40.0);
            TestValueChangeWithEventOnDM("CompletedWork", 0.0);
            TestValueChangeWithEventOnDM("CompletedWork", 1.5);
            TestValueChangeWithEventOnDM("CompletedWork", null);
            TestValueChangeWithEventOnDM("Estimate", 0.0);
            TestValueChangeWithEventOnDM("Estimate", 1.5);
            TestValueChangeWithEventOnDM("Estimate", -45.1);
            TestValueChangeWithEventOnDM("Estimate", null);
            TestValueChangeWithEventOnDM("RemainingWork", 0.0);
            TestValueChangeWithEventOnDM("RemainingWork", 1.5);
            TestValueChangeWithEventOnDM("RemainingWork", -41.9);
            TestValueChangeWithEventOnDM("RemainingWork", null);
        }

        [TestMethod]
        public void TestCustomValueChangedEvent()
        {
            TestValueChangeWithEventOnDL(
                DataObjectSchema[TestFieldDefinitionSet.ActivatedByFieldName],
                "5");
            TestValueChangeWithEventOnDL(
                DataObjectSchema[TestFieldDefinitionSet.ActivatedByFieldName],
                null);
        }

        [TestMethod]
        public void TestSchemaFieldDefaultValue()
        {
            Task task9 = Context.Projects[Resources.Project1Id].Stories[Resources.UserStory4Id].Tasks[Resources.Task5Id];
            
            // task 9 does not contain a value -> it must return the default value
            Assert.AreEqual(2, task9[DataObjectSchema[TestFieldDefinitionSet.PriorityFieldName]]);
        }

        [TestMethod]
        public void TestCustomValueGetMeta()
        {
            Assert.IsNotNull(ToTest.ItemType.FieldMeta.TryGetByName(TestFieldDefinitionSet.ActivatedByFieldName));
        }

        [TestMethod]
        public void TestParentEvent()
        {
            Task testObject = ToTest;
            UserStory newParent1 = Context.Projects[Resources.Project1Id].Iterations[Resources.Iteration1Id].Stories[Resources.UserStory3Id];
            UserStory newParent2 = Context.Projects[Resources.Project1Id].Stories[Resources.UserStory4Id];

            testObject.FireParentChangedEvent = false;
            TestAssertParentChangedFired(testObject, newParent1.Tasks, false);

            testObject.FireParentChangedEvent = true;
            TestAssertParentChangedFired(testObject, newParent2.Tasks, true);
        }

        [TestMethod]
        public override void TestParent()
        {
            Assert.IsNotNull(ToTest.Parent);
        }

        [TestMethod]
        public void TestTasksAvailable()
        {
            Assert.AreEqual(Resources.FullTask1IdChain, Context.Projects[Resources.Project1Id].Stories[Resources.UserStory1Id].Tasks[Resources.Task1Id].IdChain);
            Assert.AreEqual(Resources.FullTask2IdChain, Context.Projects[Resources.Project2Id].Stories[Resources.UserStory2Id].Tasks[Resources.Task2Id].IdChain);
            Assert.AreEqual(Resources.FullTask3IdChain, Context.Projects[Resources.Project2Id].Stories[Resources.UserStory2Id].Tasks[Resources.Task3Id].IdChain);
            Assert.AreEqual(Resources.FullTask4IdChain, Context.Projects[Resources.Project1Id].Iterations[Resources.Iteration1Id].Stories[Resources.UserStory3Id].Tasks[Resources.Task4Id].IdChain);
            Assert.AreEqual(Resources.FullTask5IdChain, Context.Projects[Resources.Project1Id].Stories[Resources.UserStory4Id].Tasks[Resources.Task5Id].IdChain);
        }

        [TestMethod]
        public void TestMemberIdGet()
        {
            Assert.AreEqual(DataObject[DataObjectSchema.MemberId], ValueChain<string>.Empty);
        }

        [TestMethod]
        public void TestMemberIdSet()
        {
            Member newMember = ToTest.Context.Projects[Resources.Project1Id].Members[Resources.Member2Id];
            ToTest.AssignedMember = newMember;
            Assert.AreEqual(DataObject[DataObjectSchema.MemberId], newMember.IdChain);
        }

        [TestMethod]
        public void TestMove()
        {
            // move to new parent
            Task toTest = ToTest;
            UserStory oldParent = (UserStory)toTest.Parent;
            UserStory newParent = Context.Projects[Resources.Project1Id].Iterations[Resources.Iteration1Id].Stories[Resources.UserStory3Id];
            newParent.Tasks.Add(toTest);
            Assert.IsNotNull(newParent.Tasks[toTest.Id]);

            // move to old parent
            oldParent.Tasks.Add(toTest);
            Assert.IsNotNull(oldParent.Tasks[toTest.Id]);
        }

        [TestMethod]
        public void TestMoveNew()
        {
            // move to new parent
            UserStory oldParent = (UserStory)ToTest.Parent;
            Task toTest = oldParent.Tasks.AddNew();

            UserStory newParent = Context.Projects[Resources.Project1Id].Iterations[Resources.Iteration1Id].Stories[Resources.UserStory3Id];
            newParent.Tasks.Add(toTest);
            Assert.IsNotNull(newParent.Tasks[toTest.Id]);

            // move to old parent
            oldParent.Tasks.Add(toTest);
            Assert.IsNotNull(oldParent.Tasks[toTest.Id]);
        }

        [TestMethod]
        public void TestStateSet()
        {
            TestStateSet(ActiveState, ClosedState);
            TestStateSet(ClosedState, InProgressState);
        }

        [TestMethod]
        public void TestStateSetWithUndoManager()
        {
            Assert.IsFalse(Context.UndoManager.CanUndo);
            TestStateSet(ActiveState, ClosedState);
            Assert.IsTrue(Context.UndoManager.CanUndo);
            TestStateSet(ClosedState, InProgressState);
            Assert.IsTrue(Context.UndoManager.CanUndo);
        }

        [TestMethod]
        public void TestStateReady()
        {
            Assert.IsTrue(!ToTest.ItemType.HasStrictWorkflow);
            Assert.IsTrue(ToTest.StateIsReady);

            ToTest.State = InProgressState;
            Assert.IsTrue(ToTest.StateIsReady);
            Assert.IsTrue(ToTest.CanChangeState(ClosedState));
        }

        /// <summary>
        /// Gets the default schema of the instance to test.
        /// </summary>
        /// <param name="schema">Specifies the parent schema instance.</param>
        /// <returns>Returns the retrieved schema instance.</returns>
        protected override TaskSchema GetSchema(ScrumTableV1Schema schema)
        {
            return schema.TaskSchema;
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}
